﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Services.Client;

namespace webjies.Services
{
    public static class QueryExtensions
    {
        public static string ToID(this DataLayer.JieEntity entity)
        {
            return entity.PartitionKey;
        }
        public static string ToID(this DataLayer.JieNodeEntity entity)
        {
            return entity.RowKey;
        }
        public static string ToID(this DataLayer.JieUrlEntity entity)
        {
            return entity.RowKey;
        }

        public static JieRef ToJieRef(this DataLayer.JieEntity entity)
        {
            return new JieRef() { ID = entity.ToID(), 
                                    Description = entity.Description, 
                                    Title = entity.Title };
        }

        public static DataLayer.JieEntity FinByKey(this DataServiceQuery<DataLayer.JieEntity> query, string id)
        {
            string partitionKey = id;
            string rowKey = "0";

            return query.Where(p => p.PartitionKey == partitionKey && p.RowKey == rowKey).SingleOrDefault();
        }

        public static IEnumerable<DataLayer.JieNodeEntity> FindByJie(this DataServiceQuery<DataLayer.JieNodeEntity> query, DataLayer.JieEntity jie)
        {
            string partitionKey = jie.PartitionKey;

            return query.Where(p => p.PartitionKey == partitionKey).ToList();
        }

        public static IEnumerable<DataLayer.JieTagEntity> FindByJie(this DataServiceQuery<DataLayer.JieTagEntity> query, DataLayer.JieEntity jie)
        {
            string partitionKey = jie.PartitionKey;

            return query.Where(p => p.PartitionKey == partitionKey).ToList();
        }

        public static IEnumerable<DataLayer.JieUrlEntity> FindByJie(this DataServiceQuery<DataLayer.JieUrlEntity> query, DataLayer.JieEntity jie)
        {
            string partitionKey = jie.PartitionKey;

            return query.Where(p => p.PartitionKey == partitionKey).ToList();
        }

        public static JieObj ToJieObj(this DataLayer.JieEntity jie, DataLayer.TableStorage storage)
        {
            var nodes = storage.Query<DataLayer.JieNodeEntity>().FindByJie(jie);
            var tags = storage.Query<DataLayer.JieTagEntity>().FindByJie(jie);
            var urls = storage.Query<DataLayer.JieUrlEntity>().FindByJie(jie);

            JieObj map = new JieObj();
            map.Description = jie.Description;
            map.ID = jie.ToID();
            map.Tags = string.Join(",", tags.Select(p => p.RowKey));
            map.Title = jie.Title;

            var firstLevelNodes = from n in nodes 
                                  orderby n.Position
                                  select n.ToJieNode(urls);

            map.Nodes.AddRange(firstLevelNodes);

            return map;
        }

        public static JieNode ToJieNode(this DataLayer.JieNodeEntity entity, IEnumerable<DataLayer.JieUrlEntity> urls)
        {
            JieNode node = new JieNode();
            node.Title = entity.Title;
            node.ID = entity.ToID();
            node.Position = entity.Position;
            node.URL = entity.URL;

            var subNodes = from n in urls
                           where n.NodeID == entity.ToID()
                            select n.ToJieUrl();

            node.URLs.AddRange(subNodes);

            return node;
        }

        public static JieUrl ToJieUrl(this DataLayer.JieUrlEntity entity)
        {
            JieUrl url = new JieUrl();
            url.ID = entity.ToID();
            url.URL = entity.URL;

            return url;
        }

        public static void UpdateJieEntity(this JieObj jie, DataLayer.JieEntity entity)
        {
            entity.PartitionKey = jie.ID.ToString();
            entity.RowKey = "0";
            entity.Title = jie.Title;
            entity.Description = jie.Description;
        }

        public static void UpdateJieTags(this JieObj jie, DataLayer.JieEntity entity, DataLayer.TableStorage storage)
        {
            IEnumerable<DataLayer.JieTagEntity> existingTags = storage.Query<DataLayer.JieTagEntity>().FindByJie(entity);

            IEnumerable<string> currentTags;
            if (!string.IsNullOrWhiteSpace(jie.Tags))
                currentTags = jie.Tags.Split(',').Select(p => p.Trim().ToUpper());
            else
                currentTags = new string[0];

            foreach (var tag in currentTags)
            {
                //new
                if (!existingTags.Any(p => string.Equals(p.RowKey, tag, StringComparison.InvariantCultureIgnoreCase)))
                    storage.Add(new DataLayer.JieTagEntity() { PartitionKey = jie.ID, RowKey = tag } );
            }

            foreach (var tag in existingTags)
            {
                //delete
                if (!currentTags.Any(p => string.Equals(p, tag.RowKey, StringComparison.InvariantCultureIgnoreCase)))
                    storage.Delete(tag);
            }
        }

        public static void UpdateJieNodes(this JieObj jie, DataLayer.JieEntity entity, DataLayer.TableStorage storage)
        {
            IEnumerable<DataLayer.JieNodeEntity> existingNodes = storage.Query<DataLayer.JieNodeEntity>().FindByJie(entity);

            foreach (var node in jie.Nodes)
            {
                if (string.IsNullOrEmpty(node.ID))
                {
                    node.ID = Guid.NewGuid().ToString();

                    //new
                    storage.Add(new DataLayer.JieNodeEntity()
                                                            {
                                                                PartitionKey = jie.ID,
                                                                RowKey = node.ID,
                                                                Position = node.Position,
                                                                Title = node.Title,
                                                                URL = node.URL
                                                            });
                }
                else
                {
                    //update
                    DataLayer.JieNodeEntity nodeEntity = existingNodes.SingleOrDefault(p => string.Equals(p.RowKey, node.ID, StringComparison.InvariantCultureIgnoreCase));
                    if (nodeEntity == null)
                        throw new ApplicationException("Node not found");

                    nodeEntity.Position = node.Position;
                    nodeEntity.Title = node.Title;
                    nodeEntity.URL = node.URL;

                    storage.Update(nodeEntity);
                }
            }

            //delete
            foreach (var node in existingNodes)
            {
                if (!jie.Nodes.Any(p => string.Equals(p.ID, node.RowKey, StringComparison.InvariantCultureIgnoreCase)))
                    storage.Delete(node);
            }

            UpdateJieUrls(jie, entity, storage);
        }

        static void UpdateJieUrls(this JieObj jie, DataLayer.JieEntity entity, DataLayer.TableStorage storage)
        {
            IEnumerable<DataLayer.JieUrlEntity> existingUrls = storage.Query<DataLayer.JieUrlEntity>().FindByJie(entity);

            foreach (var node in jie.Nodes)
            {
                foreach (var url in node.URLs)
                {
                    if (string.IsNullOrEmpty(url.ID))
                    {
                        url.ID = Guid.NewGuid().ToString();

                        //new
                        storage.Add(new DataLayer.JieUrlEntity()
                        {
                            PartitionKey = jie.ID,
                            RowKey = url.ID,
                            URL = url.URL,
                            NodeID = node.ID
                        });
                    }
                    else
                    {
                        DataLayer.JieUrlEntity urlEntity = existingUrls.SingleOrDefault(p => string.Equals(url.ID, p.RowKey, StringComparison.InvariantCultureIgnoreCase));
                        if (urlEntity == null)
                            throw new ApplicationException("Url not found");

                        //update
                        urlEntity.URL = node.URL;

                        storage.Update(urlEntity);
                    }
                }
            }

            foreach (var urlEntity in existingUrls)
            {
                //delete
                var url = (from n in jie.Nodes from u in n.URLs 
                           where string.Equals(u.ID, urlEntity.RowKey, StringComparison.InvariantCultureIgnoreCase)
                           select u).SingleOrDefault();
                if (url == null)
                    storage.Delete(urlEntity);
            }
        }
    }
}